/*
 * ====================================================================
 * Copyright (c) 2002-2018 The RapidSVN Group.  All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (in the file GPL.txt).
 * If not, see <http://www.gnu.org/licenses/>.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://rapidsvn.tigris.org/.
 * ====================================================================
 */
#ifndef _ACTION_H_
#define _ACTION_H_

// svncpp
#include <model/MyTagApp.h>
#include "svncpp/path.hpp"
#include "svncpp/revision.hpp"
#include "svncpp/status.hpp"
#include "svncpp/status_selection.hpp"
// wxWidgets
#include "wx/string.h"

// forward declarations
class Tracer;
class wxWindow;
class GitAction;
class GitContext;

namespace svn
{
    class Context;
    class StatusSel;
    class Targets;
}

/**
 *
 */
enum ACTION_TYPE {
    ACTION_UNKNOWN, ACTION_NORMAL, ACTION_SVN, ACTION_GIT
};

struct AbstractAction {
protected:
    ACTION_TYPE actionType = ACTION_UNKNOWN;
public:
    //
    virtual ACTION_TYPE getActionType() const
    {
        return this->actionType;
    }
    /**
    * Prepare action. This method is execute in the main
    * thread. You can use this method for user interaction.
    * Make sure to call @a SvnAction::Prepare in every class
    * that inherits from @a SvnAction. Make sure you check the
    * returned value as well.
    *
    * Return false to cancel action
    *
    * @see ActionWorker
    *
    * @retval true continue
    * @retval false cancel
    */
    virtual bool Prepare() = 0;


    /**
     * perform action. if any error occurs, an exception
     * will be thrown.
     */
    virtual bool Perform() = 0;

    /**
    * @return parent
    */
    //wxWindow * GetParent();
};

/*
 *
 */
class NormalAction: public AbstractAction
{
protected:
    ACTION_TYPE actionType = ACTION_NORMAL;
    wxWindow * parent;
    wxString name;

    /** flags for the action */
    unsigned int flags;
    Tracer *tracer;
    bool ownTracer;
    MyTagApp* myTagApp;
public:

    ACTION_TYPE getActionType() const override
    {
        return this->actionType;
    }

    bool Prepare() override;
    bool Perform() override;

    NormalAction ( MyTagApp* myTagApp, wxWindow * parent, const wxString & name );

    wxWindow * GetParent();

    const wxString &GetName()
    {
        return name;
    };

    /**
     * @return Tracer instance
     */
    Tracer * GetTracer();

    /**
     * Sets the tracer passed as an argument.
     * If own is TRUE, then the @a SvnAction class
     * is responsible for deleting the tracer.
     */
    void SetTracer ( Tracer * t, bool own );
    /**
     * output message with the tracer
     */
    void Trace ( const wxString & msg );

    /**
     * output error message with the tracer
     */
    void TraceError ( const wxString & msg );
};

/**
 * Inherit from this class
 * and use the constructor to pass parameters to the class.
 *
 * Use the class @a ActionWorker to run actions.
 *
 * @see ActionWorker
 */
class SvnAction: public NormalAction
{
public:
    /**
     * if set then no files have changed after this
     * operation and we dont have to update the filelist
     *
     * @see GetFlags
     */
    static const unsigned int DONT_UPDATE;

    /**
     * if set then the files wont be changed immediately.
     * To detect this one can set a flag and update later,
     * when the application gets activated again
     * (action opened different application, user applied
     * changes, saved them and comes back to rapidsvn
     * later -> BOOM, update)
     *
     * @remarks Use either @a DONT_UPDATE or @a UPDATE_LATER
     */
    static const unsigned int UPDATE_LATER;

    /**
     * if set then the tree will be updated as well.
     */
    static const unsigned int UPDATE_TREE;

    SvnAction ( MyTagApp* myTagApp, wxWindow * parent, const wxString & name,
                unsigned int flags = 0 );
    /**
     * destructor
     */
    virtual ~SvnAction();

    /**
     * set actions parent window
     *
     * @param parent the parent that will receive events
     */
    void SetParent ( wxWindow * parent );

    /**
     * @return parent
     */
    //wxWindow * GetParent();

    /**
     * sets the context for this action
     *
     * @param context
     */
    void SetSvnContext (svn::Context * context );

    /**
     * @return the context of the action
     */
    svn::Context * GetSvnContext();

    bool Prepare () override;

    /**
     * sets the path for the action
     *
     * @param path
     */
    void SetPath ( const svn::Path & path );

    /**
     * @return path
     */
    const svn::Path & GetPath();

    /**
     * sets a selection of @ref Status for the action.
     * Not every action will need it.
     *
     * The contents of @a statusSel will be copied
     *
     * @param targets
     */
    void SetStatusSel ( const svn::StatusSel & statusSel );

    /**
     * @return the status selection for this action
     */
    const svn::StatusSel & GetStatusSel() const;

    /**
     * @return the statuses for this action
     */
    const svn::StatusVector & GetStatusVector() const;

    /**
     * @return the targets for this action
     */
    const svn::Targets & GetTargets() const;

    /**
     * @return a single target for this action
     */
    svn::Path GetTarget() const;

    /**
     * retrieves the flags for this action.
     *
     * @see DONT_UPDATE
     */
    unsigned int GetFlags() const;

    void SetName ( const wxString & name );

    /** returns the name of the action */
    //const wxString &GetName() const;
    /**
      * retrieves a file @a path with @a revision
      * settings from the repository and write it to
      * a temporary file
      *
      * @return temporary filename
      */
    svn::Path
    GetPathAsTempFile (
            const svn::Path & path,
            const svn::Revision & revision = svn::Revision::HEAD );

    SvnAction() = delete;

    SvnAction ( const SvnAction & ) = delete;

    ACTION_TYPE getActionType() const override
    {
        return this->actionType;
    }

protected:
    //struct Data;
    // this structure contains implementation specific data
    //Data * m;

    /**
       * the context under which the action will be
       * performed. this includes auth info and callback
       * addresses
       */
    svn::Context * context;

    /**
     * the path where the action will take place
     */
    svn::Path path;

    svn::StatusSel statusSel;

    ACTION_TYPE actionType = ACTION_SVN;

};

class GitAction: public NormalAction
{
public:
protected:
    GitContext * context;
    wxString path;
    ACTION_TYPE actionType = ACTION_GIT;
public:
    GitAction() = delete;

    GitAction ( const GitAction & ) = delete;

    ACTION_TYPE getActionType() const override
    {
        return this->actionType;
    }

    void SetName ( const wxString & name );
};
#endif
/* -----------------------------------------------------------------
 * local variables:
 * eval: (load-file "../rapidsvn-dev.el")
 * end:
 */

